/**
 * ****************************************************************************
 * Project: RoboBridge
 * ----------------------------------------------------------------------------
 * -------------------------- [c]2012 - KrawallMann ---------------------------
 * ---------------------- http://www.krawallmann.de.tc/ -----------------------
 * ****************************************************************************
 * File: Reader.java Package: tc.de.krawallmann.robobridge.communication
 * Version: 1.0 Author(s): KrawallMann
 * ****************************************************************************
 * Description:
 * ****************************************************************************
 */
package tc.de.krawallmann.robobridge.communication;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;

import tc.de.krawallmann.robobridge.util.Exceptions;
import tc.de.krawallmann.robobridge.util.Log;

/**
 * The Class Reader reads from an InputStream.>
 * 
 * @author KrawallMann
 * @version 1.0
 */
public class Reader {

	/** The listeners. */
	public transient Set<IncomingMessageListener> listeners =
			new HashSet<IncomingMessageListener>();

	/** The buffered reader. */
	private transient BufferedReader bufferedReader;

	/** The connectedState. */
	private transient boolean connectedState;

	/**
	 * Adds the incoming message listener.
	 * 
	 * @param listener
	 *            the listener
	 * @return true, if successful
	 */
	public boolean addIncomingMessageListener(final IncomingMessageListener listener) {
		if (listener == null) {
			throw Exceptions.onNullPointer(this, "listener");
		}
		return listeners.add(listener);
	}

	/**
	 * Clear incoming message listeners.
	 */
	public void clearIncomingMessageListeners() {
		listeners.clear();
	}

	/**
	 * Close.
	 */
	public void close() {
		if (connectedState) {
			try {
				bufferedReader.close();
			} catch (final IOException exc) {
				Log.log(Level.WARNING, getClass(), "close", "Exception while closing - {0}!",
						exc.getMessage());
			}
			connectedState = false;
		}
	}

	/**
	 * Connect.
	 * 
	 * @param inputStream
	 *            the input stream
	 */
	public void connect(final InputStream inputStream) {
		if (inputStream == null) {
			throw Exceptions.onNullPointer(this, "inputStream");
		}
		if (connectedState) {
			throw new IllegalStateException("Reader already connectedState!");
		}
		bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
		connectedState = true;
	}

	/**
	 * Gets the incoming message listener count.
	 * 
	 * @return the incoming message listener count
	 */
	public int getIncomingMessageListenerCount() {
		return listeners.size();
	}

	/**
	 * Checks if the reader is connected.
	 * 
	 * @return true, if it is connected
	 */
	public boolean isConnected() {
		return connectedState;
	}

	/**
	 * Read line.
	 * 
	 * @return the string
	 * @throws IOException
	 *             Signals that an I/O exception has occurred.
	 */
	public String readLine() throws IOException {
		if (!connectedState) {
			throw new IllegalStateException("Reader: Not connectedState!");
		}
		final String message = bufferedReader.readLine();
		for (final IncomingMessageListener listener : listeners) {
			listener.onMessageReceived(message);
		}
		return message;
	}

	/**
	 * Removes the incoming message listener.
	 * 
	 * @param listener
	 *            the listener
	 * @return true, if successful
	 */
	public boolean removeIncomingMessageListener(final IncomingMessageListener listener) {
		if (listener == null) {
			throw Exceptions.onNullPointer(this, "listener");
		}
		return listeners.remove(listener);
	}
}
